"""
The MIT License (MIT)
Copyright © 2022 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-esp32-walkie-talkie
"""

'''
| ICS-43434 | ESP32 |
|-------------------|
|    WS <===> IO25  |
|    SD <===> IO26  |
|   SCK <===> IO27  |
|    LR <===> GND   |
|   GND <===> GND   |
|   VDD <===> 3V3   |
'''
from machine import Pin, I2S
import _thread
from utime import sleep_ms

BUFF_SIZE = 20000

BITS = 16
FORMAT = I2S.MONO
RATE = 16000


class Pins(object):
	BUTTON = 0

	class I2S_CODEC(object):
		SD = Pin(27)
		WS = Pin(25)
		SCK = Pin(26)

	class I2S_MIC(object):
		SD = Pin(12)
		WS = Pin(13)
		SCK = Pin(14)


class ICS43434(object):
	def __init__(self):
		self.__audio_in = None
		self.__init()

	def __init(self):
		if self.__audio_in is not None:
			return

		self.__audio_in = I2S(
			0,
			sck=Pins.I2S_MIC.SCK, 
			ws=Pins.I2S_MIC.WS,
			sd=Pins.I2S_MIC.SD,
			mode=I2S.RX,
			bits=BITS,
			format=FORMAT,
			rate=RATE,
			ibuf=BUFF_SIZE
		)

		print('ics-43434 initialized')
	
	def __deinit(self):
		self.__audio_in.deinit()
		self.__audio_in = None

	def read(self, buf):
		self.__audio_in.readinto(buf)
		I2S.shift(buf=buf, bits=16, shift=2)

		return buf
	
	def on(self):
		self.__init()
	
	def off(self):
		self.__deinit()


class MAX98357(object):
	def __init__(self):
		self.__audio_out = I2S(
			1,
			sck=Pins.I2S_CODEC.SCK, 
			ws=Pins.I2S_CODEC.WS,
			sd=Pins.I2S_CODEC.SD,
			mode=I2S.TX,
			bits=BITS,
			format=FORMAT,
			rate=RATE,
			ibuf=BUFF_SIZE
		)

		print('max98357 initialized')

	def write(self, buf):
		self.__audio_out.write(buf)


class INTERGRATED(ICS43434, MAX98357):
	def __init__(self):
		ICS43434.__init__(self)
		MAX98357.__init__(self)

		self.__wave_samples_mv = memoryview(bytearray(BUFF_SIZE))
		self.__running = True
		self.__paused = False
		self.__mic_enabled = True

		_thread.start_new_thread(self.__loop, ())
	
	def stop(self):
		self.__running = False

	def play(self):
		self.__paused = not self.__paused
		print('pause' if self.__paused else 'play')

	def switch_mic(self):
		self.__mic_enabled = not self.__mic_enabled
		print('mic on' if self.__mic_enabled else 'mic off')

		self.on() if self.__mic_enabled else self.off()

	def __loop(self):
		try:
			while self.__running:
				if not self.__paused:
					if self.__mic_enabled:
						self.__audio_in.readinto(self.__wave_samples_mv)
						I2S.shift(buf=self.__wave_samples_mv, bits=16, shift=1)
						data_length = BUFF_SIZE
					else:
						data_length = 0

					self.__audio_out.write(self.__wave_samples_mv[0:data_length])

					# self.write(self.read(self.__wave_samples_mv))

				sleep_ms(2)
		except:
			print('thread loop terminated')


def main():
	walkie = INTERGRATED()

	def button_irq(pin_instance):
		walkie.switch_mic()

	button = Pin(Pins.BUTTON, Pin.IN)
	button.irq(button_irq, Pin.IRQ_RISING)


if __name__ == '__main__':
	main()
